using Microsoft.VisualStudio.TestTools.UnitTesting;
using StockholmsStad.Data.Interfaces;
using StockholmsStad.Runtime.Serialization.DataContract;
using StockholmsStad.Runtime.Serialization.DataContract.Enums;
using System.Collections.Generic;
using System;
using StockholmsStad.Utilities.Exceptions;

namespace StockholmsStad.Data.Test
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class TestUnitUser : TestUnitBase
    {
        // before running each test 
        [TestInitialize()]
        public void MyTestInitialize()
        {
            BeginTransaction();
        }

        // after each test has run
        [TestCleanup()]
        public void MyTestCleanup()
        {
            EndTransaction();
        }

        [TestMethod]
        public void GetNonExistingUser()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            User user = userAgent.GetUser(context, "Pelle sansLÖS");
            Assert.AreEqual(null, user);
        }

        [TestMethod]
        public void InsertAndRetrieveUser()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            const string username = "username";
            const string password = "password";
            const int userRoleId = (int) UserRole.Customer;

            userAgent.CreateUser(context, username, password, userRoleId);
            User user = userAgent.GetUser(context, username);
            Assert.AreEqual(username, user.Username);
        }

        [TestMethod]
        public void InsertAndRetrieveUser2()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();

            const string username = "username";
            const string password = "password";
            const int userRoleId = (int) UserRole.Customer;
            userAgent.CreateUser(context, username, password, userRoleId);
            User user = userAgent.GetUser(context, username);
            Assert.AreEqual(username, user.Username);
            Assert.AreEqual((int)user.Role, userRoleId, "Roll id matchade inte");
        }

        [TestMethod]
        public void InsertAndRetrieveParvisUserWithCellPhone()
        {
            var userAgent = AgentFactory.GetUserAgent();
            var parvisUser = TestEntity.GetParvisUserWithCellPhone();
            const bool includeInActive = false;

            var origUsers = userAgent.GetUsers(context, includeInActive);
            string password = userAgent.CreatePassword(context);
            var id = userAgent.AddUser(context, parvisUser, password);
            Assert.AreNotEqual(0, id, "Det skapades ingen parvis användare");
            parvisUser.ParvisUserId = id;

            var retrievedUser = userAgent.GetParvisUser(context, parvisUser.ParvisUserId.Value);
            AreParvisUserEqual(parvisUser, retrievedUser);

            var users = userAgent.GetUsers(context, includeInActive);

            Assert.AreNotEqual(origUsers.Count, users.Count, "Antalet användare {0} stämmer inte överens med det förväntade {1}", 
                origUsers.Count, users.Count);

            bool found = false;
            foreach (var user in users)
            {
                if (user.ParvisUserId == id)
                {
                    found = true;
                    AreParvisUserEqual(parvisUser, user);
                }
            }

            Assert.AreEqual(true, found, "Hittade inte den tillagda användaren");
        }

        [TestMethod]
        public void InsertAndRetrieveParvisUserWithoutCellPhone()
        {
            var userAgent = AgentFactory.GetUserAgent();
            var parvisUser = TestEntity.GetParvisUserWithoutCellPhone();
            const bool includeInActive = false;

            var origUsers = userAgent.GetUsers(context, includeInActive);
            string password = userAgent.CreatePassword(context);
            var id = userAgent.AddUser(context, parvisUser, password);
            Assert.AreNotEqual(0, id, "Det skapades ingen parvis användare");
            parvisUser.ParvisUserId = id;

            var retrievedUser = userAgent.GetParvisUser(context, parvisUser.ParvisUserId.Value);
            AreParvisUserEqual(parvisUser, retrievedUser);

            var users = userAgent.GetUsers(context, includeInActive);

            Assert.AreNotEqual(origUsers.Count, users.Count, "Antalet användare {0} stämmer inte överens med det förväntade {1}",
                origUsers.Count, users.Count);

            bool found = false;
            foreach (var user in users)
            {
                if (user.ParvisUserId == id)
                {
                    found = true;
                    AreParvisUserEqual(parvisUser, user);
                }
            }

            Assert.AreEqual(true, found, "Hittade inte den tillagda användaren");
        }

        /// <summary>
        /// Giltig användare
        /// </summary>
        [TestMethod]
        public void IsValidUserTest()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            const string username = "username234234234234";
            const string password = "password234234234234";
            const int userRoleId = (int) UserRole.Customer;

            userAgent.CreateUser(context, username, password, userRoleId);
            bool validWebUser = userAgent.IsValidWebUser(context, username, password);
            Assert.AreEqual(true, validWebUser);
        }

        /// <summary>
        /// Giltig användare, men fel användarroll
        /// </summary>
        [TestMethod]
        public void IsValidUserTest2()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            const string username = "username234234234234";
            const string password = "password234234234234";
            const int userRoleId = (int) UserRole.SysAdmin;

            userAgent.CreateUser(context, username, password, userRoleId);
            bool validWebUser = userAgent.IsValidWebUser(context, username, password);
            Assert.AreEqual(false, validWebUser);
        }

        /// <summary>
        /// Ej Giltig användare
        /// </summary>
        [TestMethod]
        public void IsValidUserTest3()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            const string username = "username234234234234";
            const string password = "password234234234234";
            bool validWebUser = userAgent.IsValidWebUser(context, username, password);
            Assert.AreEqual(false, validWebUser);
        }

        [TestMethod]
        public void IsUserNameUnique()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            ITicketAgent ticketAgent = AgentFactory.GetTicketAgent();
            const string username = "username";
            const string password = "password";
            // Object
            // Test empty
            bool unique = userAgent.IsUserNameUnique(context, username);
            Assert.AreEqual(true, unique);

            int userId = userAgent.CreateUser(context, username, password, (int)UserRole.Customer);
            Assert.AreNotEqual(0, userId, "Ingen användare skapades");

            ICeremonyAgent agent = AgentFactory.GetCeremonyAgent();

            var languageAgent = AgentFactory.GetLanguageAgent();
            var langId = languageAgent.AddLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, langId, "Inget nytt språk skapades");

            var cerLangId = languageAgent.AddCeremonyLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, cerLangId, "Inget nytt ceremoni språk skapades");

            var certLangId = languageAgent.AddCertificateLanguage(context, TestEntity.NewLanguage);
            Assert.AreNotEqual(0, certLangId, "Inget nytt certifikat språk skapades");

            Ceremony ceremony = TestEntity.GetNewCeremony();
            ceremony.CeremonyLanguage.Id = cerLangId;
            ceremony.CertificateLanguage.Id = certLangId;

            int ticketId = ticketAgent.CreateTicket(context,
                                                    TestEntity.GetNewCoupleWithoutContact(), ceremony,
                                                    userId);

            Assert.AreNotEqual(0, ticketId, "Inget ärende skapades");

            // test another user
            const string username2 = "username2";
            unique = userAgent.IsUserNameUnique(context, username2);
            Assert.AreEqual(true, unique);

            int newUserId = userAgent.CreateUser(context, username2, password, (int)UserRole.Customer);
            Assert.AreNotEqual(0, userId, "Ingen användare skapades");

            int ticketId2 = ticketAgent.CreateTicket(context,
                                     TestEntity.GetNewCoupleWithoutContact(), TestEntity.GetNewCeremony(),
                                     newUserId);

            Assert.AreNotEqual(0, ticketId2, "Inget ärende skapades");
        }

        /// <summary>
        /// Ej Giltig användare
        /// </summary>
        [TestMethod]
        public void CreatePasswordTest()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            string password = userAgent.CreatePassword(context);
            Assert.IsNotNull(password);
            Assert.AreEqual(8, password.Length);
            string password2 = userAgent.CreatePassword(context);
            Assert.AreNotEqual(password, password2);
        }

        [TestMethod]
        public void AddAndRetrieveUser()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            const string username = "test@hotmail.com";
            userAgent.AddUser(context, username, 2);

            User user = userAgent.GetUser(context, username);
            Assert.IsNotNull(user, "Användaren lades inte till");
            Assert.AreEqual(user.Role, UserRole.HandlingOfficer, "Användarens roll är felaktig");
        }

        [TestMethod]
        [ExpectedException(typeof(StockholmStadSystemException))]
        public void AddAndRetrieveUserSetUserToInactive()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            var addedUser = TestEntity.GetParvisUserWithCellPhone();
            addedUser.Password = "password";
            var id = userAgent.AddUser(context, addedUser, addedUser.Password);
            Assert.AreNotEqual(0, id, "Ingen användare lades till");
            addedUser.ParvisUserId = id;
            Assert.IsNotNull(addedUser, "Användaren lades inte till");

            var retrievedUser = userAgent.GetParvisUser(context, addedUser.ParvisUserId.Value);

            Assert.IsNotNull(retrievedUser, "Hittade inte den skapade användaren");
            AreParvisUserEqual(addedUser, retrievedUser);

            userAgent.SetUserInactive(context, addedUser.Username);
            userAgent.GetParvisUser(context, addedUser.ParvisUserId.Value); // Expected exception
        }

        [TestMethod]
        public void AddAndRetrieveUserRoles()
        {
            IUserAgent userAgent = AgentFactory.GetUserAgent();
            var allRoles = new List<UserRole> ();
            var excludeRoles = new List<UserRole> { UserRole.SuperUser, UserRole.Customer };
            var expectedRoles = userAgent.GetRoles(context, excludeRoles);
            var allExpectedRoles = userAgent.GetRoles(context, allRoles);

            Assert.AreEqual(allExpectedRoles.Count - excludeRoles.Count, expectedRoles.Count, "Antalet roller matchar inte");

            // Roller returneras i bokstavsordning (svenska)
            Assert.AreEqual(UserRole.Customer, allExpectedRoles[0]);
            Assert.AreEqual(UserRole.HandlingOfficer, allExpectedRoles[1]);
            Assert.AreEqual(UserRole.ReadOnly, allExpectedRoles[2]);
            Assert.AreEqual(UserRole.SuperUser, allExpectedRoles[3]);
            Assert.AreEqual(UserRole.SysAdmin, allExpectedRoles[4]);
        }

        private static void AreParvisUserEqual(ParvisUser expected, ParvisUser retrieved)
        {
            Assert.AreEqual(expected.FirstName, retrieved.FirstName);
            Assert.AreEqual(expected.LastName, retrieved.LastName);
            Assert.AreEqual(expected.CellPhoneNumber, retrieved.CellPhoneNumber);
            Assert.AreEqual(expected.PhoneNumber, retrieved.PhoneNumber);
            Assert.AreEqual(expected.ParvisUserId, retrieved.ParvisUserId);
            Assert.AreEqual(expected.Username, retrieved.Username);
            Assert.AreEqual(expected.Role, retrieved.Role);
        }
    }
}